package core;

import api.FetchResetPasswordLinkFromEmail;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.util.ReUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import dao.ProxyConfig;
import dao.Result;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import utils.LoggerUtile;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class UpdataZingPwd {
 static String userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36";
  static String account ;
  static String password  ;
 static ProxyConfig proxyConfig;

 static Proxy proxy = null;
  static String emailAccount;
 static String emailPassword;
 static LoggerUtile logger ;
 static String addr_uiautomator2;
 static CompletableFuture<Result> future;

 private static JSONObject config;
    private static int resolveCaptcha2Count;
    private static String apikey;
    private static String captchToken;
    private static long checkResetPwdLinkStartTime;
    private static long emailSendStartTime;

    public static CompletableFuture<Result> start(Map m, String addr) {
     future = new CompletableFuture<>();
     new Thread(()->{
        config = (JSONObject) JSONObject.parse((String) m.get("data"));
        logger=LoggerUtile.getLogger("zp-pwd-update-"+config.get("haoId")+config.get("orderId"));
        proxyConfig = (ProxyConfig) m.get("proxyConfig");
        emailAccount = (String) config.get("emailAccount");
        emailPassword = (String) config.get("emailPassword");
        account = (String) config.get("account");
        password = (String) config.get("password");
         addr_uiautomator2 = addr;
        // Assuming you have equivalent functions for 'handleCompleted', 'rejectCallback', and 'logger.info'.
        logger.info("开始处理任务" + "account:" + account + " password:" + password);
        getApiKey();
     }).start();

          return future;
    }
 // 获取找回密码链接
     private static void getApiKey() {
      try {
       logger.info("开始获取apikey");
       String body = HttpRequest.get("https://id.zing.vn/").execute().body();
       apikey = extractApiKey(body,"apikey=([a-z0-9]+)");
       logger.info("获取apikey完成", apikey);
       resolveCaptcha2Count = 0;
       getCaptcha2Token();
      } catch(Exception e) {
       logger.error("请求apiKey异常", e.getMessage());
       future.complete(new Result(-1,"请求apiKey异常",e.getMessage()));
      }

     }

    // 获取验证码
    private static void getCaptcha2Token() {
        try {
            logger.info("开始获取captcha2token");
            String callback = "zmCore." + String.valueOf((int) (Math.random() * 100000));
            String captchaTokenResponse = HttpRequest.post("https://captcha2.zing.vn/captcha2/gettoken")
                    .form("publicKey", apikey)
                    .form("callback", callback)
                    .execute().body();


            captchToken = extractApiKey(captchaTokenResponse,"\"token\":\"([a-z0-9]+)\"");
            logger.info("获取captcha2token完成", captchToken);
            getCaptcha2Image();
        } catch(Exception error) {
            logger.error("请求验证码链接异常", error.getMessage() );
            future.complete(new Result(-1,"请求验证码链接异常",error.getMessage()));
        }
    }

    // 获取验证码图片
    private static void getCaptcha2Image() {
        try {
           logger.info("开始获取captcha2图片");

            HttpResponse execute = HttpRequest.get("https://captcha2.zing.vn/captcha2/getcaptcha")
                    .header("Content-Type", "application/json")
                    .form("publicKey", apikey)
                    .form("token", captchToken)
                    .execute();
            byte[] captchaResponse = execute.bodyBytes();

            String base64Data = Base64.encode(captchaResponse);
            logger.info("获取captcha2图片完成", base64Data.substring(0, 32));
            captcha2ImageToText(base64Data);
        } catch(Exception e){
            logger.error("请求验证码图片异常" ,e.getMessage());
            future.complete(new Result(-1,"请求验证码图片异常",e.getMessage()));
        }
    }
    // 识别验证码
    private static void captcha2ImageToText(String base64Data) {
        try {
           logger.info("开始获取识别验证码");

            cn.hutool.json.JSONObject taskData = JSONUtil.createObj()
                    .set("type", "ImageToTextTaskTest")
                    .set("body", base64Data);

            cn.hutool.json.JSONObject requestData = JSONUtil.createObj()
                    .set("clientKey", "11ad877f9a5f2002bfc6220e83ff9bd7e458ce8d26149")
                    .set("task", taskData);
            String captchaResultResponse2 = HttpRequest.post("https://api.yescaptcha.com/createTask")
                    .body(requestData.toString())
                    .execute().body();

            JSONObject captchaResultResponse = (JSONObject) JSONObject.parse(captchaResultResponse2);
            logger.info("验证码识别结果", captchaResultResponse.get("solution"));

            if (captchaResultResponse.get("solution")!=null) {
                if (resolveCaptcha2Count >= 10) {
                    logger.error("验证码错误次数过多",captchaResultResponse);
                    future.complete(new Result(1,"验证码错误次数过多",captchaResultResponse));
                    return;
                }
                resolveCaptcha2Count++;
                getCaptcha2Token();
                // this.getCaptcha2Image()
                return;
            }
            submitCaptcha2(captchaResultResponse.get("solution"));
        } catch(Exception error) {
            logger.error("识别验证码异常" ,error.getMessage());
            future.complete(new Result(-1,"识别验证码异常",error.getMessage()));
        }
    }
    // 提交验证
    private static void submitCaptcha2(Object solution) {
        try {
            logger.info("开始提交验证码");
            String body = HttpRequest.post("https://id.zing.vn/v2/forgotinfo")
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .form("tokenCaptcha", captchToken)
                    .form("aliasname", account)
                    .form("forgotType", "password")
                    .form("captcha", solution)
                    .form("apikey", apikey).execute().body();
            JSONObject data = (JSONObject) JSONObject.parse(body);
            Document doc = Jsoup.parse(body);

            // Extract values from the HTML document
            Element errAliasElement = doc.selectFirst("#errAlias");
            String errAlias = (errAliasElement != null) ? errAliasElement.val() : null;

            Element errCaptchaElement = doc.selectFirst("#errCaptcha");
            String errCaptcha = (errCaptchaElement != null) ? errCaptchaElement.val() : null;

            Element isSendMailDisabledElement = doc.selectFirst("#changePwdByEmail");
            boolean isSendMailDisabled = (isSendMailDisabledElement != null && isSendMailDisabledElement.hasAttr("disabled"));

            if (isSendMailDisabled) {
                logger.error("账号无法发送邮件",body,account);
                future.complete(new Result(1,"账号无法发送邮件",account));
                return;
            }

            if (errAlias!=null || body.contains("Rất tiếc")) {
                logger.error("不存在的账号",body,account);
                future.complete(new Result(1,"不存在的账号",account));
                return;
            }

            if (errCaptcha!=null) {
                logger.info("验证码错误重试第"+resolveCaptcha2Count + "次");

                // 错误超过10次 @TODO 验证最多提交错误次数是不是会被封锁
                if (resolveCaptcha2Count >= 10) {
                    logger.error("验证码错误次数过多",body);
                    future.complete(new Result(1,"验证码错误次数过多",body));
                    return;
                }
                getCaptcha2Image();
                resolveCaptcha2Count++;
                return;
            }

            JSONObject request = (JSONObject) data.get("request");
            JSONObject res =(JSONObject) request.get("res");
            String url = (String) res.get("responseUrl");
            //captchTokenResponse?.request?.res?.responseUrl

            if (url == null) {
                logger.error("提交验证码失败" ,body);
                future.complete(new Result(1,"提交验证码失败",body));
                return;
            }

            URL urlInstance = new URL(url);
            String query = urlInstance.getQuery();
            if (query != null) {
                Map<String, String> params = getParameters(query);
                String pid = params.get("pid");
                String forgetToken = params.get("token");
                logger.info("提交验证码完成", url, forgetToken, pid);
                submitForgotPassRequest(pid, forgetToken);
            }
        }catch (Exception e){
            logger.error("提交验证码异常", e.getMessage());
            future.complete(new Result(-1,"提交验证码异常",e.getMessage()));
        }
    }
    // 发送密码修改邮件
    private static void submitForgotPassRequest(String pid, String forgetToken) {
        try {
            logger.info("开始发送重置密码邮件");
            emailSendStartTime = System.currentTimeMillis();
            HttpRequest request = HttpRequest.post("https://id.zing.vn/v2/forgotpass")
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .form("tokenCaptcha", "")
                    .form("changePwdBy", "email")
                    .form("apikey", apikey)
                    .form("pid", pid)
                    .form("token", forgetToken);

            // Send the POST request
            String forgotPassResponse = request.execute().body();

            // Check if the response contains the success message
            boolean isSuccess = forgotPassResponse.contains("Hệ thống đã gửi email cho bạn qua hộp thư đã đăng ký với Zing ID.");
            if (!isSuccess) {
                logger.error("发送重置密码邮件失败", forgotPassResponse);
                future.complete(new Result(1,"发送重置密码邮件失败",forgotPassResponse));
                return;
            }

            logger.info("发送重置密码邮件完成");
            checkResetPwdLinkStartTime = System.currentTimeMillis();
            getResetPasswordURL();
        }catch (Exception e){
            logger.error("发送密码重置邮件异常" , e.getMessage());
            future.complete(new Result(-1,"发送密码重置邮件异常",e.getMessage()));
        }
    }

    private static void getResetPasswordURL() {
        logger.info("开始查询改密邮件", emailAccount, emailPassword);

        // 超过三分钟还没查到结束
      long time = System.currentTimeMillis() - checkResetPwdLinkStartTime;
        if (time > 3 * 60 * 1000) {
            logger.error("查询改密邮件超时", time);
            future.complete(new Result(-1,"查询改密邮件超时",time));
            return;
        }
        try {
            Map dm=new HashMap();
            dm.put("account",account);
            dm.put("password",password);
            dm.put("taskCode","zingspeed_forgot_password");
            String s = FetchResetPasswordLinkFromEmail.fetchResetPasswordLinkFromEmail(addr_uiautomator2, JSON.toJSONString(dm));
            JSONObject parse = (JSONObject) JSONObject.parse(s);
            JSONObject data = (JSONObject) parse.get("data");
            if (data.get("link")!=null || (long)data.get("receiveTime") * 1000 < emailSendStartTime) {
                logger.info("改密链接非当前任务发送的邮件 重试", data);
                // Retry the operation after 30 seconds
                try {
                    Thread.sleep(1000 * 30);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                getResetPasswordURL();
                return;
            }

            logger.info("改密链接查询结果", data);
            updatePassword((String) data.get("link"));
        }catch (Exception e){
            // 一分钟后重试
            logger.error("改密链接查询异常", e.getMessage());
            try {
                Thread.sleep(1000 * 30);
                getResetPasswordURL();
            } catch (InterruptedException e2) {
                e2.printStackTrace();
            }
        }
    }

    private static void updatePassword(String url2) {
        try {
           logger.info("开始修改密码");

            String body = HttpRequest.get(url2).execute().body();
            JSONObject data = (JSONObject) JSONObject.parse(body);

            JSONObject request = (JSONObject) data.get("request");
            JSONObject res =(JSONObject) request.get("res");
            String url = (String) res.get("responseUrl");
            if(url==null || url.contains("activationkey")){
                logger.info("非法的重置密码链接", body ,url);
                future.complete(new Result(1,"非法的重置密码链接",url));
                return;
            }
            Random random = new SecureRandom();
            // 定义密码字符集
            String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            // 定义密码长度
            int length = 10;
            // 生成密码
            StringBuilder password1 = new StringBuilder("@U");
            for (int i = 0; i < length - 2; i++) {
                char randomChar = characters.charAt(random.nextInt(characters.length()));
                password1.append(randomChar);
            }
            String nextPassword = password1.toString();
            logger.info("生成新密码", nextPassword);
            String body1 = HttpRequest.post(url)
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .form("activationkey", "")
                    .form("uname", "")
                    .form("tokenCaptcha", "")
                    .form("new_password", nextPassword)
                    .form("confirm_password", nextPassword).execute().body();

            boolean isSuccess = body1.contains("resetpass_success");

            if (!isSuccess) {
                logger.error("提交修改密码失败", body1);
                future.complete(new Result(1,"提交修改密码失败",nextPassword));
                return;
            }

            logger.info("提交修改密码成功",body1);
            future.complete(new Result(0,"提交修改密码成功",nextPassword));
        }catch (Exception error){
            logger.error("提交修改密码请求异常", error.getMessage());
           future.complete(new Result(-1,"提交修改密码请求异常",error.getMessage()));
        }
    }

    public static Map<String, String> getParameters(String query) {
        Map<String, String> params = new HashMap<>();
        String[] keyValuePairs = query.split("&");

        for (String pair : keyValuePairs) {
            String[] keyValue = pair.split("=");
            if (keyValue.length == 2) {
                String key = keyValue[0];
                String value = keyValue[1];
                params.put(key, value);
            }
        }

        return params;
    }

    private static String extractApiKey(String data,String regex) {
        return ReUtil.getGroup1(regex, data);
    }


}
